<?php
/**
 * 
 * Copyright (c) 2008 Jerry Jalava <jerry.jalava@gmail.com>
 * Licensed under the GPLv3 license
 * http://www.gnu.org/licenses/gpl.html
 * 
 */

require_once "HTTP/Request.php";

class couchdb_transport
{
    private $configuration;
    private $tmp_conf = array();
    
    protected $lastStatusCode;
    protected $lastRevision;
    protected $lastDocId;
    
    public function __construct(&$configuration)
    {
        if (   empty($configuration)
            || !isset($configuration['host'])
            || !isset($configuration['port']))
        {
            throw new couchdb_transport_exception('Invalid config defined for transport');
        }
        
        $this->configuration = $configuration;
    }
    
    public function free_execute($url=false, $options='GET', $postdata=false, $headers=array(), $tmp_conf=array())
    {
        if (! empty($tmp_conf))
        {
            $this->set_tmp_config($tmp_conf);
        }
        
        return $this->execute($url, $options, $postdata, $headers);
    }
    
    public function set_tmp_config($config)
    {
        $this->tmp_conf = $this->configuration;
        
        foreach ($config as $key => $value)
        {
            $this->tmp_conf[$key] = $value;
        }        
    }
    
    private function parse_params($params)
    {
        if (   !isset($params[0])
            || (   $params[0] !== false
                && $params[0] == ''))
        {
            throw new couchdb_transport_exception('No url defined for transport');
        }
        
        $config = $this->configuration;
        if (! empty($this->tmp_conf))
        {
            $config = $this->tmp_conf;
        }
        
        $postdata = false;
        $headers = array(
            'Content-Type' => 'text/javascript'
        );        
        $options = array(
            'method' => 'GET',
            'allowRedirects' => true,
            'timeout' => 3
        );    
        
        $suffix = "";

        if (   isset($config['database'])
            && !empty($config['database']))
        {
            $suffix = "{$config['database']}/";
        }
        
        if (! is_null($params[0]))
        {
            $suffix .= "{$params[0]}";
        }
        
        $url = "http://{$config['host']}:{$config['port']}/{$suffix}";

        if (count($params) >= 2)
        {
            if (is_array($params[1]))
            {
                foreach ($params[1] as $key => $value)
                {
                    $options[$key] = $value;
                }
            }
            else
            {
                $options['method'] = strtoupper($params[1]);
            }            
        }
        
        if (count($params) >= 3)
        {
            $postdata = $params[2];
        }
        
        if (   count($params) == 4
            && is_array($params[3]))
        {
            foreach ($params[3] as $key => $value)
            {
                $headers[$key] = $value;
            }
        }
        
        $this->tmp_conf = array();
        
        return array(
            $url,
            $options,
            $postdata,
            $headers
        );
    }
    
    private function clean_json($json)
    {
		$json = preg_replace('/"_rev":([0-9]+)/', '"_rev":"$1"', $json);		
		return json_decode($json);
    }
    
    protected function execute()
    {        
        list($url, $options, $postdata, $headers) = $this->parse_params(func_get_args());
        
		$req = new HTTP_Request($url, $options);
		
		if ($postdata)
		{
			$req->addRawPostData($postdata);
            // var_dump("POST-DATA: $postdata");
		}
		
		if ($headers)
		{
			if (   isset($headers['_rev'])
			    && !empty($headers['_rev']))
			{
				$req->addHeader('_rev', (float) $headers['_rev']);
			}

			if (   isset($headers['Content-Type'])
			    && !empty($headers['Content-Type']))
			{
				$req->addHeader('Content-Type', $headers['Content-Type']);
			}
		}
		
		$resp = $req->sendRequest();
		
		if (PEAR::isError($resp))
		{
			throw new couchdb_transport_exception('Unexpected error occured while sending the request!' . $resp);
		}
		
		$this->lastStatusCode = $req->getResponseCode();
		
		if ($this->lastStatusCode == 404)
		{
		    throw new couchdb_transport_exception("Requested url {$url} not found.", 404);
		}
		
		if (! in_array($this->lastStatusCode, range(200, 299)))
		{
			throw new couchdb_transport_exception("Don't know how to handle response with code {$this->lastStatusCode}.");
		}
		
		$this->lastRevision = $req->getResponseHeader('x-couch-revid');
		$this->lastDocId = $req->getResponseHeader('x-couch-docid');
        
		return $this->clean_json($req->getResponseBody());
    }
}

?>